Race Condition (RC)

Description:

A field is accessed in at least one place within a synchronized section (with locked monitors), and in one or more other places, it is accessed without locking any monitor or with locking a different monitor.

RC analyzes all thread entry points in the program. By default, entry points are determined as methods passed to the constructor of delegate System.Threading.ThreadStart. However, it is possible to treat any public method as an entry point (it is useful for library functions that can be invoked in any context). Then the resource analyzer recursively builds resource lock closure, by traversing all method invocation from entry points and keeping track of locked resources. As a result of such analysis, we detect fields that can be concurrently accessed by different threads (it is assumed that all code reachable from the entry points is reentrant) and know the set of locked monitors protecting such access. If access to the same field is performed with an inconsistent set of locked monitors, then the Race Condition message is produced. Inconsistent, in this context, means that at least one set is not empty and an intersection of all sets is empty. If a field is accessed without any locked monitor, then the Field is accessed concurrently without locking message is produced, otherwise the Field is accessed concurrently with different lock sets message is produced. To minimize the number of false race conditions detected, this audit considers only update access to the fields, so if a field is not modified, a message will not be produced.

Incorrect:

class Account {
    private long amount;

    public void Deposit(int sum) { 
        lock (this) { 
            amount += sum;
        }
    }

    public void AccumulatePersents(float percent) {
        amount += (long)(amount * percent); // here 'amount' is accessed without lock
    }
}

Correct:

class Account {
    private long amount;

    public void Deposit(int sum) { 
        lock (this) { 
            amount += sum;
        }
    }

    public void AccumulatePersents(float percent) {
        lock (this) {   
            amount += (long)(amount * percent);
        }
    }
}